using System;
using Microsoft.SPOT;

namespace Robot
{
    class PWM : IDisposable
    {
        ushort m_factor = 25;
        Microsoft.SPOT.Hardware.OutputPort m_port = null;
        System.Threading.Thread m_thread = null;
        bool m_continue = true;

        public PWM(Microsoft.SPOT.Hardware.Cpu.Pin pin) : this(pin, 100) { }

        public PWM(Microsoft.SPOT.Hardware.Cpu.Pin pin, ushort freq)
        {
            m_port = new Microsoft.SPOT.Hardware.OutputPort(pin, false);
            m_thread = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
            DutyCycle = 0;
            Frequency = freq;
            m_thread.Start();
        }

        /// <summary>
        /// Gets and sets duty cycle of PWM signal
        /// </summary>
        public byte DutyCycle { get; set; }

        /// <summary>
        /// Gets and sets frequency of PWM signal
        /// </summary>
        public ushort Frequency
        {
            get
            {
                return (ushort)(10000 / m_factor);
            }
            set
            {
                m_factor = (ushort)(10000 / value);
            }
        }

        /// <summary>
        /// Implements the PWM algorithm
        /// </summary>
        private void Run()
        {
            System.Diagnostics.Debug.Print("PWM running (" + m_port.Id.ToString() + ")");
            while (m_continue)
            {
                // Special case - If DC == 0, keep it low
                if (DutyCycle == 0)
                {
                    m_port.Write(false);
                    MicroSleep.Microsleep(100 * m_factor);
                }
                // Special case - If DC == 100, keep it high
                else if (DutyCycle >= 100)
                {
                    m_port.Write(true);
                    MicroSleep.Microsleep(100 * m_factor);
                }
                // Normal operation
                else
                {
                    // Set output pin high
                    m_port.Write(true);
                    // Wait
                    MicroSleep.Microsleep(DutyCycle * m_factor);
                    // Set output pin low
                    m_port.Write(false);
                    // Wait
                    MicroSleep.Microsleep((100 - DutyCycle) * m_factor);
                }
            }
        }


        #region IDisposable Members

        public void Dispose()
        {
            m_continue = false;
        }

        #endregion
    }
}
